package com.mytx.sso.controller;

import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.domain.AlipayFundCouponOrderAppPayModel;
import com.alipay.api.domain.AlipayFundTransToaccountTransferModel;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.*;
import com.alipay.api.response.AlipayFundTransToaccountTransferResponse;
import com.alipay.api.response.AlipaySystemOauthTokenResponse;
import com.alipay.api.response.AlipayTradeAppPayResponse;
import com.alipay.api.response.AlipayUserInfoShareResponse;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.mytx.common.config.MytxConfig;
import com.mytx.common.annotation.SerializedField;
import com.mytx.common.constant.Constant;
import com.mytx.common.pojo.CommonResult;
import com.mytx.common.pojo.RedisLock;
import com.mytx.common.utils.*;
import com.mytx.mapper.*;
import com.mytx.pojo.*;
import com.mytx.sso.config.AliPayConfig;
import com.mytx.sso.service.ConsumerSearchService;
import com.mytx.sso.utils.OrderInfoUtil2_0;
import com.mytx.sso.utils.PayUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;

import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;

import java.text.DecimalFormat;
import java.text.ParseException;
import java.util.*;
import java.util.concurrent.TimeUnit;


@SuppressWarnings({"Duplicates", "SpringJavaInjectionPointsAutowiringInspection"})
@RestController
public class AliPayController {
    private static Logger logger = LoggerFactory.getLogger(AliPayController.class);

    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    AliPayConfig aliPayConfig;
    @Autowired
    RechargeMapper rechargeMapper;
    @Autowired
    UserMapper userMapper;
    @Autowired
    AlipayClient alipayClient;

    @Autowired
    private ConsumerSearchService searchService;

    @Autowired
    ContactMapper contactMapper;
    @Autowired
    TransferMapper transferMapper;
    @Autowired
    CouponMapper couponMapper;
    @Autowired
    private HttpServletRequest request;
    @Autowired
    private UserController userController;


    private static Integer reqCount = 0; //用户申请提现的总次数

    private static Integer count; //管理员个数


    /**
     * 生成支付链接
     *
     * @param body
     * @return
     * @throws AlipayApiException
     */
    @PostMapping("/alipayUrl")
    public CommonResult doPost(@Valid @RequestBody JSONObject body) throws AlipayApiException {
        String uId = request.getHeader("uId");
        AlipayTradeAppPayRequest alipayRequest = new AlipayTradeAppPayRequest();
        //设置异步回调地址
        alipayRequest.setNotifyUrl(aliPayConfig.NOTIFY_URL_PAY);
        AlipayTradeAppPayModel model = body.toJavaObject(AlipayTradeAppPayModel.class);
        String orderItemId = IDUtils.genOrderItemId();
        logger.info("订单号码:orderItemId:{}", orderItemId);
        model.setOutTradeNo(orderItemId);
        alipayRequest.setBizModel(model);
        AlipayTradeAppPayResponse response = alipayClient.sdkExecute(alipayRequest);
        if (response.isSuccess()) {
            logger.info("支付链接生成成功");
        } else {
            logger.info("支付链接生成链接");
        }
        String aliPayUrl = response.getBody();
        logger.info("生成的支付的链接:alipayUrl:{}", aliPayUrl);
        Recharge recharge = new Recharge();
        recharge.setGmtPayment(new Date());
        recharge.setId(orderItemId);
        recharge.setuId(uId);
        recharge.setAmount(new BigDecimal(model.getTotalAmount()));
        recharge.setTradeStatus(Constant.ORDER_RECHARGE_PAY_STATUS);
        //缓存到redis
        redisTemplate.opsForValue().set(Constant.RECHARGE_KEY + orderItemId, recharge, 25, TimeUnit.HOURS);//25小时到期
        return CommonResult.ok(aliPayUrl);
    }


    /**
     * 服务器端验签
     *
     * @param body
     * @return
     * @throws AlipayApiException
     */
    @PostMapping("/alipayValidateSign")
    public CommonResult alipayValidateSign(@RequestBody JSONObject body) throws AlipayApiException {
        String uId = request.getHeader("uId");
        String content = body.getString("content");
        String sign = body.getString("sign");
        logger.info("aliPayValidateSign-->alipayValidateSign 支付同步通知验签:" + content, sign);
        boolean flag = AlipaySignature.rsa256CheckContent(content, sign, aliPayConfig.ALI_PAY_PUBLIC_KEY, aliPayConfig.CHARSET);
        if (!flag) {
            logger.error("支付同步通知验签失败-用户id:" + uId, content, sign);
            return CommonResult.build(Constant.VALIDATE_SIGN_FAIL, "支付同步通知验签失败");
        }
        //检查充值订单是否存在
        JSONObject jsonObject = JSONObject.parseObject(content);
        String out_trade_no = jsonObject.getString("out_trade_no");
        RedisLock redisLock = new RedisLock(redisTemplate, Constant.USER_SESSION_LOCK + out_trade_no);
        try {
            boolean isGetLock = true;
            if (!redisLock.lock()) {
                logger.info("支付同步通知:没有获取到锁" + content);
                isGetLock = false;
                //  return CommonResult.build(CommonResult.STATUS_FAIL, UserService.REDIS_HAD_LOCK);这儿注销掉，是因为即使没获取到锁，也不影响同步通知的验签，并且验证通过必须给用户的余额做增加操作。
            }
            String key = Constant.USER_SESSION + uId;

            //检查支付订单号是否匹配
            Object s = redisTemplate.opsForValue().get(Constant.RECHARGE_KEY + out_trade_no);
            if (s == null) {
                logger.error("支付定单不存在-用户id:" + uId, content);
                return CommonResult.build(Constant.RECHARGE_ORDING_INFO_ERROR, "充值订单找不到缓存记录");
            }
            Recharge originalRecharge = (Recharge) s;
            //检查金额是否匹配
            DecimalFormat df = new DecimalFormat("######0.00");
            String total_amount = jsonObject.getString("total_amount");
            BigDecimal totalAmount = new BigDecimal(total_amount);
            logger.info("支付宝金额:total_amount:{}", total_amount);
            logger.info("支付订单中的金额:totalAmount:{}", totalAmount);
            if (originalRecharge.getAmount().compareTo(totalAmount) != 0) {
                logger.error("支付金额与原始订单不一致-用户id:" + uId, content);
                return CommonResult.build(Constant.RECHARGE_ORDING_INFO_ERROR, "充值金额与缓存中的订单金额不一致");
            }
            //检查卖家号是否匹配
            String seller_id = jsonObject.getString("seller_id");
            if (!StringUtils.equals(seller_id, aliPayConfig.PID)) {
                logger.error("支付定单信息中卖家号信息不符-用户id:" + uId, content);
                return CommonResult.build(Constant.RECHARGE_ORDING_INFO_ERROR, "支付定单信息中卖家号信息不符");
            }
            //检查app_id
            String app_id = jsonObject.getString("app_id");
            if (!StringUtils.equals(app_id, aliPayConfig.APP_ID)) {
                logger.error("支付定单信息中app_id不符-用户id:" + uId, content);
                return CommonResult.build(Constant.RECHARGE_ORDING_INFO_ERROR, "支付定单信息中app_id不符");
            }
            BigDecimal newBalance;
            //没有获取到锁,isGetLock=false,这样就不用更新redis的数据和持久化数据进mysql了，因为异步通知先达到我们服务端，这些操作已经做了。
            if (isGetLock && StringUtils.equals(originalRecharge.getTradeStatus(), Constant.ORDER_RECHARGE_PAY_STATUS)) {
                newBalance = userMapper.incrementBalance(uId, originalRecharge.getAmount());
                redisTemplate.opsForHash().put(Constant.USER_SESSION + uId, Constant.BALANCE, newBalance);
                originalRecharge.setTradeStatus(Constant.ORDER_OK_PAY_STATUS);//1 表示此支付订单，已经持久化到mysql,
                redisTemplate.opsForValue().set(Constant.RECHARGE_KEY + out_trade_no, originalRecharge);//把状态更新到redis，是为了让后来的异步通知，能获取该笔支付订单的状态
                originalRecharge.setTradeNo(jsonObject.getString("trade_no"));
                //更新余额成功
                logger.info("同步通知到达更新余额成功,订单信息:uid:{},orderId:{},orderStatus:{},更新后的余额:newBalance:{}", uId, originalRecharge.getTradeNo(), originalRecharge.getTradeStatus(), newBalance);
                rechargeMapper.insertSelective(originalRecharge);
            } else {
                //走到这儿，说明是支付异步通知先到达，只需要读取缓存中的余额返回给前端
                newBalance = new BigDecimal(redisTemplate.opsForHash().get(Constant.USER_SESSION + uId, "balance").toString());// TODO: 2018/9/10 如果没获取到锁，这儿读取的余额是否是脏数据？
                logger.info("订单信息:uid:{},orderId:{},orderStatus:{},更新后的余额:newBalance:{}", uId, originalRecharge.getTradeNo(), originalRecharge.getTradeStatus(), newBalance);
            }

            return CommonResult.ok(newBalance);
        } catch (InterruptedException e) {
            e.printStackTrace();
            logger.error("支付同步通知验签出错：" + e.getMessage());
            return CommonResult.build(400, "支付同步通知验签出错：" + e.getMessage());
        } finally {
            redisLock.unlock();
        }

    }


    /**
     * 支付宝异步通知
     *
     * @param request
     * @return
     * @throws AlipayApiException
     * @throws UnsupportedEncodingException
     * @throws ParseException
     */
    @RequestMapping(value = "/alipayNotify", method = RequestMethod.POST)
    @SerializedField(encrypt = false)
    public String alipayNotify(HttpServletRequest request) throws AlipayApiException, UnsupportedEncodingException, ParseException {

        Map<String, String> params = analyzeRequestParams(request);
        logger.info("alipayNotify:支付异步通知验签:" + params);

        boolean flag = checkSign(params);
        if (!flag) {
            logger.error("支付异步通知验签失败" + params);
            return "fail";
        }
        String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"), "UTF-8");
        //支付宝交易号
        String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"), "UTF-8");

        //卖家支付宝账号
        String buyer_id = new String(request.getParameter("buyer_id").getBytes("ISO-8859-1"), "UTF-8");
        //买家登录支付宝账户名：一般是邮箱，中间被*号隐藏
        String buyer_logon_id = new String(request.getParameter("buyer_logon_id").getBytes("ISO-8859-1"), "UTF-8");
        //交易时间
        String gmt_payment = new String(request.getParameter("gmt_payment").getBytes("ISO-8859-1"), "UTF-8");
        //交易金额
        String invoice_amount = new String(request.getParameter("invoice_amount").getBytes("ISO-8859-1"), "UTF-8");
        //交易状态
        String trade_status = new String(request.getParameter("trade_status").getBytes("ISO-8859-1"), "UTF-8");
        RedisLock redisLock = new RedisLock(redisTemplate, Constant.USER_SESSION_LOCK + out_trade_no);
        try {
            if (!redisLock.lock()) {
                logger.info("支付异步通知:没有获取到锁" + request.getParameterMap().toString());
                return "fail";//没有获取到锁，说明同步通知先达到，并占用了锁，返回fail,支付宝那边会在其他时间段，再次post异步通知的，
            }
            Object s = redisTemplate.opsForValue().get(Constant.RECHARGE_KEY + out_trade_no);
            Recharge recharge;
            if (s != null) {
                recharge = (Recharge) s;

            } else {
                logger.error("支付异步通知：redis中没有原始订单信息" + params);
                recharge = new Recharge();
                recharge.setId(out_trade_no);
            }
            //更新、完善支付订单的信息,当时同步通知出现问题，比如用户手机在支付成功的瞬间 没电关机了，要确保用户支付订单要保存进数据库，方便人工核对查询
            recharge.setTradeNo(trade_no);
            recharge.setAmount(new BigDecimal(invoice_amount));
            recharge.setGmtPayment(DateUtils.getDateByStr(gmt_payment));
            recharge.setBuyerId(buyer_id);
            recharge.setBuyerLogonId(buyer_logon_id);
            logger.info("支付订单的信息:uid:{},orderId:{},trade_no,status:{},amount:{}", recharge.getuId(), recharge.getTradeNo(), trade_no, recharge.getTradeStatus(), recharge.getAmount());
            //原始订单信息存在
            if (s != null) {
                //原始订单信息 的交易状态为1，说明在同步通知中，已经持久化到mysql了，这儿就做更新操作
                if (StringUtils.equals(recharge.getTradeStatus(), Constant.ORDER_OK_PAY_STATUS)) {
                    recharge.setTradeStatus(trade_status);
                    rechargeMapper.updateByPrimaryKeySelective(recharge);
                    logger.info("同步通知先到达更新余额的状态");
                } else {

                    if (StringUtils.equals(trade_status, "TRADE_SUCCESS")) {
                        //获取用户信息，并对用户余额做增加操作
                        String uId = recharge.getuId();
                        BigDecimal mysqlBalance = userMapper.incrementBalance(uId, recharge.getAmount());
                        redisTemplate.opsForHash().put(Constant.USER_SESSION + uId, Constant.BALANCE, mysqlBalance);
                        logger.info("异步通知先到达,更新数据库中的用户余额:uid:{},orderId:{},tarade_no:{},tatus:{},mysqlBalance:{}",
                                recharge.getuId(), recharge.getTradeNo(), trade_no, recharge.getTradeStatus(), mysqlBalance);
                    }
                    //更新状态到redis,让后到达的同步通知，知道该笔支付订单的状态，如果有类似greenDao的insertOrUpdate（）方法，是不是就可以不用加锁了
                    recharge.setTradeStatus(trade_status);
                    redisTemplate.opsForValue().set(Constant.RECHARGE_KEY + out_trade_no, recharge);
                    rechargeMapper.insertSelective(recharge);
                    logger.info("更新缓存中的状态:uid:{},orderId:{},tarade_no:{},tatus:{},mysqlBalance:{}", recharge.getuId(),
                            recharge.getTradeNo(), trade_no, recharge.getTradeStatus());

                }
            } else {
                //即使原始订单信息不存在，也把充值订单信息持久化到mysql,状态设置为2，以备后续查询
                recharge.setTradeStatus(Constant.ORDER_ERROR_PAY_STATUS);
                rechargeMapper.insertSelective(recharge);
                logger.info("原始订单信息不存在,异常订单,订单信息:uid:{},orderId:{},trade_no,status:{},amount:{}",
                        recharge.getuId(), recharge.getTradeNo(), trade_no, recharge.getTradeStatus(), recharge.getAmount());
            }
        } catch (InterruptedException e) {
            e.printStackTrace();

        } finally {
            redisLock.unlock();
        }
        return "success";
    }


    /**
     * 获取充值详细信息
     *
     * @param body
     * @return
     */
    @PostMapping("/getRechargeRecord")
    public CommonResult getRechargeRecord(@RequestBody JSONObject body) {
        String uId = request.getHeader("uId");
        int page = 1;
        int size = 10;
        if (body.containsKey("page")) {
            page = body.getInteger("page");
        }
        if (body.containsKey("size")) {
            size = body.getInteger("size");
        }
        RechargeExample example = new RechargeExample();
        RechargeExample.Criteria criteria = example.createCriteria();
        criteria.andUIdEqualTo(uId);
        PageHelper.startPage(page, size);
        List<Recharge> rechargeList = rechargeMapper.selectByExample(example);
        PageInfo<Recharge> rechargePageInfo = new PageInfo<>(rechargeList);
        return CommonResult.ok(rechargePageInfo);
    }

    @PostMapping("/redirectUri")
    public String redirectUri() {

        return null;
    }

    /**
     * 手动提现(申请提现)
     *
     * @param body
     * @return
     * @throws AlipayApiException
     */
    @PostMapping("/transfer")
    @SerializedField(encrypt = false)
    public CommonResult transfer(@RequestBody JSONObject body) throws AlipayApiException {
        String uId = request.getHeader("uId");
        RedisLock redisLock = new RedisLock(redisTemplate, Constant.USER_SESSION_LOCK, 1);
        try {
            if (!redisLock.lock()) {
                return CommonResult.build(Constant.GET_LOCK_FAIL, "没有获取到锁");
            }
            String payPassword = body.getString("payPasssword");
            String aliAccount = body.getString("aliAccount");
            BigDecimal amount = new BigDecimal(body.getString("amount"));
            logger.info("转账的金额:" + amount);
            //更新到数据库中
            User addAliAccountUser = new User();
            addAliAccountUser.setAliAccount(aliAccount);
            addAliAccountUser.setuId(uId);
            int count = userMapper.updateByPrimaryKeySelective(addAliAccountUser);
            logger.info("需要转账的支付宝账户:uId:{},aliAccount:{}", uId, aliAccount);
            redisTemplate.opsForHash().put(Constant.USER_SESSION + uId, "aliAccount", aliAccount);
            logger.info("支付宝账户绑定成功");
            User myUser = getUser(uId);
            CommonResult commonResult = PayUtils.payPrepare(payPassword, amount, myUser);
            if (commonResult != null) {
                return commonResult;
            }
            Transfer transfer = new Transfer();
            transfer.setId(IDUtils.genUUID());
            transfer.setuId(uId);
            transfer.setAliUid(myUser.getAliUid());
            transfer.setAliAccount(myUser.getAliAccount());
            transfer.setAmount(amount);
            transfer.setOrderId(IDUtils.genOrderItemId());
            transfer.setStatus(Constant.ORDER_TRANSFER_APPLY_STATUS);
            Date createDate = new Date();
            transfer.setCreateDate(createDate);
            transferMapper.insertSelective(transfer);
            BigDecimal mysqlDeposit = userMapper.incrementDeposit(uId, amount);
            redisTemplate.opsForHash().put(Constant.USER_SESSION + uId, Constant.DEPOSIT, mysqlDeposit);
            logger.info("transfer:提现申请成功,保证金增加,uId:{},orderId:{},status:{},amount:{},mysqlDeposit:{},createDate", uId, transfer.getOrderId(),
                    transfer.getStatus(), amount, mysqlDeposit, createDate);
            // TODO: 2019/5/21 应该要推送一条消息给管理员用户
            Message notify = new Message();
            notify.setVisible(Constant.MESSAGE_VISIBLE);
            notify.setType(Constant.PUSH_MESSAGE_ORDER_TRANSFER);
            //封装申请用户的信息
            User targetUser = new User();
            targetUser.setuId(myUser.getuId());
            targetUser.setUsername(myUser.getUsername());
            targetUser.setAliAccount(myUser.getAliAccount());
            targetUser.setNick(myUser.getNick());
            targetUser.setAvatar(myUser.getAvatar());
            transfer.setTargetUser(targetUser);
            notify.setExtraData(transfer);
            //推送申请提现信息给管理员
            JSONObject info = new JSONObject();
            info.put("userIdList",getTransferAdminId());
            info.put("message",notify);
            redisTemplate.convertAndSend(Constant.NOTIFY_PUSH_MESSAGE,info );
            //返回新的保证金结果
            return CommonResult.ok(mysqlDeposit);
        } catch (Exception e) {
            e.printStackTrace();
            return CommonResult.build(Constant.RETURN_HTTP_STATUS_ERROR, "申请提现失败");
        } finally {
            redisLock.unlock();
        }

    }

    /**
     * 提现订单成功(扣余额)
     *
     * @return
     */
    @PostMapping("/transferSuccess")
    @SerializedField(encrypt = false)
    public CommonResult transferSuccess(@RequestBody JSONObject body) {
        //1.获取当前管理员的用户id
        String uId = request.getHeader("uId");
        RedisLock redisLock = new RedisLock(redisTemplate, Constant.USER_SESSION_LOCK, 1);
        try {
            if (!redisLock.lock()) {
                return CommonResult.build(Constant.GET_LOCK_FAIL, "没有获取到锁");
            }
            //2.解析前端返回的参数
            String targetId = body.getString("targetId");//申请提现的用户id
            String orderId = body.getString("orderId");//提现的订单id
            logger.info("transferSuccess:申请提现的信息:targetId:{},adminId:{},orderId:{}", targetId, uId, orderId);
            //3.获取申请提现的用户信息
            User targetUser = getUser(targetId);
            logger.info("即将修改提现成功的用户信息:uId:{},username:{},phone:{},blance:{},depoist:{}", targetId,
                    targetUser.getUsername(), targetUser.getPhone(), targetUser.getBalance(), targetUser.getDeposit());
            //4.获取申请提现的订单信息
            TransferExample transferExample = new TransferExample();
            TransferExample.Criteria criteria = transferExample.createCriteria();
            criteria.andOrderIdEqualTo(orderId);
            List<Transfer> transferList = transferMapper.selectByExample(transferExample);
            //判断申请的订单信息是否存在
            if (transferList.size() > 0) {
                Transfer transfer = transferList.get(0);
                String transferId = transfer.getId();

                if (transfer.getStatus() == Constant.ORDER_TRANSFER_SUCCESS_STATUS) {
                    logger.error("transferSuccess: 重复提现  transferId：{}", transferId);
                    return CommonResult.build(CommonResult.STATUS_FAIL, "该笔提现已经是成功状态，不能重复发起提现操作");
                }
                BigDecimal transferAmount = transfer.getAmount();
                logger.info("申请提现的订单信息:id:{},aliUid:{},aliAccount:{},amount:{},status:{}createTime:{}", transferId,
                        transfer.getAliUid(), transfer.getAliAccount(), transferAmount, transfer.getStatus(), transfer.getCreateDate());
                //5减少保证金,减少余额,并更新缓存中的数据
                User user = userMapper.reduceDonationAmount(transferAmount, targetId);
                targetUser.setBalance(user.getBalance());
                targetUser.setDeposit(user.getDeposit());
                redisTemplate.opsForHash().putAll(Constant.USER_SESSION + targetId, EntityUtils.objectToMap_v1(targetUser));
                //6.修改提现订单状态
                Transfer newTransfer = new Transfer();
                newTransfer.setId(transferId);
                newTransfer.setStatus(Constant.ORDER_TRANSFER_SUCCESS_STATUS);
                newTransfer.setTargetUser(user);
                newTransfer.setAdminId(uId);
                newTransfer.setTargetUser(targetUser);
                Date payDate = new Date();
                newTransfer.setPayDate(payDate);
                newTransfer.setUpdateDate(payDate);
                transferMapper.updateByPrimaryKeySelective(newTransfer);
                JSONObject info = new JSONObject();
                info.put("uId", targetId);
                redisTemplate.convertAndSend(Constant.NOTIFY_SYNC_USER_INFO, info);
                logger.info("修改提现订单状态成功:orderId:{},amount:{},status:{},createTime:{},payTime:{}", orderId, transferAmount, Constant.ORDER_STATUS_OFFER_SUCCESS
                        , transfer.getCreateDate(), transfer.getPayDate());
                return CommonResult.ok(newTransfer);
            }
            logger.error("提现订单不存在:orderId:{}", orderId);
            return CommonResult.build(Constant.RETURN_HTTP_STATUS_TRANSFER_ORDER_NOT_EXIST, "提现订单不存在");
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("transferSuccess:系统出现错误:" + e.getMessage());
            return CommonResult.build(Constant.RETURN_HTTP_STATUS_ERROR, "提现订单处理失败");
        } finally {
            redisLock.unlock();
        }
    }

    /**
     * 处理异常提现订单
     *
     * @param body
     * @return
     */
    @PostMapping("/transferError")
    @SerializedField(encrypt = false)
    public CommonResult transferException(@RequestBody JSONObject body) {
        //1.获取处理管理员的用户id
        String uId = request.getHeader("uId");
        String tragetId = body.getString("tragetId");//申请提现的用户id
        String orderId = body.getString("orderId");//提现的订单id
        logger.info("transferSuccess:申请提现的信息:targetId:{},adminId:{},orderId:{}", tragetId, uId, orderId);
        TransferExample transferExample = new TransferExample();
        TransferExample.Criteria criteria = transferExample.createCriteria();
        criteria.andOrderIdEqualTo(orderId);
        List<Transfer> transferList = transferMapper.selectByExample(transferExample);
        //判断申请的订单信息是否存在
        if (transferList.size() > 0) {
            Transfer transfer = transferList.get(0);
            String transferId = transfer.getId();
            BigDecimal transferAmount = transfer.getAmount();
            logger.info("申请提现的异常订单信息:id:{},aliUid:{},aliAccount:{},amount:{},status:{}createTime:{}", transferId,
                    transfer.getAliUid(), transfer.getAliAccount(), transferAmount, transfer.getStatus(), transfer.getCreateDate());
            Transfer newTransfer = new Transfer();
            newTransfer.setId(transferId);
            newTransfer.setStatus(Constant.OREDER_TRANSFER_ERROR_STATUS);
            newTransfer.setAdminId(uId);
            Date payDate = new Date();
            newTransfer.setPayDate(payDate);
            newTransfer.setUpdateDate(payDate);
            transferMapper.updateByPrimaryKeySelective(newTransfer);
            logger.info("修改提现订单为异常状态成功:orderId:{},amount:{},status:{},createTime:{},payTime:{}", orderId, transferAmount, Constant.OREDER_TRANSFER_ERROR_STATUS
                    , transfer.getCreateDate(), newTransfer.getPayDate());
            return CommonResult.ok(newTransfer);
        }
        logger.error("提现订单不存在:orderId:{}", orderId);
        return CommonResult.build(Constant.RETURN_HTTP_STATUS_TRANSFER_ORDER_NOT_EXIST, "提现订单不存在");
    }


    /**
     * 提现
     *
     * @param amount
     * @return
     * @throws AlipayApiException
     */
//    @PostMapping("/transfer")
    public CommonResult transfer1(@RequestBody String amount) throws AlipayApiException {
        // TODO: 2019/5/21 因为现在不能申请支付宝转账接口,所以现在手动转账,后续再写自动转账
        String uId = request.getHeader("uId");
        RedisLock redisLock = new RedisLock(redisTemplate, Constant.USER_SESSION_LOCK, 1);
        try {
            if (!redisLock.lock()) {
                return CommonResult.build(Constant.GET_LOCK_FAIL, "没有获取到锁");
            }
            logger.info("转账的金额:" + amount);
            String key = Constant.USER_SESSION + uId;
            Object userInfo = redisTemplate.opsForValue().get(key);
            User myUser = (User) userInfo;
            //判断用户余额
            BigDecimal balance = myUser.getBalance();

            if (balance.compareTo(new BigDecimal(amount)) < 0) {
                logger.error("转账余额不足:", amount, myUser);
                return CommonResult.build(Constant.BALANCE_NOT_ENOUGH, "余额不足");
            }

            AlipayFundTransToaccountTransferRequest request = new AlipayFundTransToaccountTransferRequest();
            AlipayFundTransToaccountTransferModel model = new AlipayFundTransToaccountTransferModel();
            model.setOutBizNo(IDUtils.genOrderItemId());
            // model.setPayeeType("ALIPAY_USERID");
            // model.setPayeeAccount(myUser.getAliUid());
            model.setPayeeType("ALIPAY_LOGONID");
            model.setPayeeAccount("ugwery6485@sandbox.com");
            model.setAmount(amount);
            model.setPayerShowName("蚂蚁同行");
            //   model.setPayeeRealName("转账真实名字");
            model.setRemark("提现");
            request.setBizModel(model);

            AlipayFundTransToaccountTransferResponse response = alipayClient.execute(request);
            if (response.isSuccess()) {
                logger.info("转账-提现完成" + response.getBody(), myUser);
                if (StringUtils.equals(response.getCode(), "10000")) {
                    Transfer transfer = new Transfer();
                    transfer.setId(response.getOutBizNo());
                    transfer.setuId(myUser.getuId());
                    transfer.setAliUid(myUser.getAliUid());
                    transfer.setAmount(new BigDecimal(amount));
                    transfer.setOrderId(response.getOrderId());
                    transfer.setPayDate(DateUtils.getDateByStr(response.getPayDate()));
                    transferMapper.insertSelective(transfer);
                    //对用户余额进行减少操作
                    BigDecimal mysqlBalance = userMapper.reduceBalance(uId, new BigDecimal(amount));
                    redisTemplate.opsForHash().put(key, "balance", mysqlBalance.doubleValue());
                    logger.info("transfer:提现 用户余额减少,uId:{},amount:{},balance:{}", uId, amount, mysqlBalance);

                    //返回新的余额结果
                    return CommonResult.ok(mysqlBalance);
                }

            } else {
                logger.error("转账(提现)失败" + response.getBody(), amount, myUser);
            }
            return CommonResult.ok();
        } catch (InterruptedException e) {
            e.printStackTrace();
            return CommonResult.build(Constant.ALI_SYSTEM_ERROR, "支付宝系统错误");
        } finally {
            redisLock.unlock();
        }

    }

    /**
     * 获取支付宝登录授权链接
     *
     * @return
     * @throws AlipayApiException
     */
    @PostMapping("/getAuthUrl")
    //  @SerializedField(encrypt = false, addEncodeFlag = true)
    public CommonResult getAuthUrl(@RequestBody(required = false) Object body) throws AlipayApiException {
        Map<String, String> authInfoMap = OrderInfoUtil2_0.buildAuthInfoMapV1(aliPayConfig.PID, aliPayConfig.APP_ID, IDUtils.genOrderId(), true);
        String info = OrderInfoUtil2_0.buildOrderParam(authInfoMap);
        String sign = OrderInfoUtil2_0.getSign(authInfoMap, aliPayConfig.PRIVATE_KEY, true);
        final String authInfo = info + "&" + sign;
        logger.info("请求支付宝授权链接" + authInfo);
        return CommonResult.ok(authInfo);
    }

    /**
     * 支付宝授权登录
     *
     * @param info
     * @return
     * @throws AlipayApiException
     */
    @PostMapping("/aliAuthLogin")
//    @SerializedField(encrypt = false)
    public CommonResult aliAuthLogin(@RequestBody(required = false) Map<String, String> info) throws AlipayApiException {

        CommonResult commonResult = getAliPayUserInfo(info);
        if (!Constant.RETURN_HTTP_STATUS_SUCCESS.equals(commonResult.getStatus())) {
            return commonResult;
        }
        AlipayUserInfoShareResponse shareResponse = (AlipayUserInfoShareResponse) commonResult.getData();
        String aliUid = shareResponse.getUserId();
        UserExample example = new UserExample();
        UserExample.Criteria criteria = example.createCriteria();
        criteria.andAliUidEqualTo(aliUid);
        List<User> tbUsers = userMapper.selectByExample(example);
        if (tbUsers != null && tbUsers.size() != 0) {
            //说明是老用户
            User user = tbUsers.get(0);
            String salt = Utils.genSalt();
            String token = JwtTokenUtils.genToken(salt, user.getuId());
            String key = Constant.USER_SESSION + user.getuId();
            user.setSalt(salt);

            try {
                redisTemplate.opsForHash().putAll(key, EntityUtils.objectToMap_v1(user));
            } catch (Exception e) {
                e.printStackTrace();
            }
            redisTemplate.expire(key, Constant.LOGIN_EXPIRE_TIME, TimeUnit.DAYS);
            //查询mysql中的联系人
            List<Contact> contacts = contactMapper.queryContacts(user.getuId());
            //当前登录的用户在tid时，将tGroupName设置为GroupName
            for (Contact contact : contacts) {
                if (StringUtils.equals(user.getuId(), contact.gettId())) {
                    String tGroupName = contact.gettGroupName();
                    contact.setGroupName(tGroupName);
                }
            }
            user.setSalt(null);
            user.setPassword(null);
            user.setPayPassword(null);
            Map<String, Object> resultMap = new HashMap<>();
            resultMap.put("token", token);
            resultMap.put("userInfo", user);
            resultMap.put("contacts", contacts);
            return CommonResult.ok(resultMap);

        } else {
            //说明是新用户，生成新的用户信息，持久化到mysql
            User newRegisterUser = new User();
            newRegisterUser.setuId(IDUtils.genUUID());
            newRegisterUser.setAliUid(aliUid);
            newRegisterUser.setCreated(new Date());
            newRegisterUser.setAvatar(shareResponse.getAvatar());
            String username = "支付宝用户_" + aliUid;
            newRegisterUser.setUsername(username);
            newRegisterUser.setNick(shareResponse.getNickName());
            newRegisterUser.setArea(shareResponse.getCity());
            newRegisterUser.setCreated(new Date());
            String aliGender = shareResponse.getGender();
            if (StringUtils.equals(aliGender, Constant.RETURN_ALIPAY_GENDER_MALE)) {
                newRegisterUser.setGender(Constant.DATA_BASE_GENDER_MALE);
            } else if (StringUtils.equals(aliGender, Constant.RETURN_ALIPAY_GENDER_FEMALE)) {
                newRegisterUser.setGender(Constant.DATA_BASE_GENDER_FEMALE);
            }
            newRegisterUser.setPassword(DigestUtils.md5DigestAsHex(Constant.INITIAL_PASSWORD.getBytes()));
            //保存到数据库中
            userMapper.insertSelective(newRegisterUser);
            //保存用户信息到ES
            Topic userInfoTopic = new Topic();
            userInfoTopic.setId(newRegisterUser.getuId());//让保存用户信息的topic id 和用户id 相同
            userInfoTopic.setType(Constant.TOPIC_TYPE_USER_INFO);
            User saveToES = new User();
            saveToES.setuId(newRegisterUser.getuId());
            saveToES.setUsername(newRegisterUser.getUsername());
            saveToES.setAvatar(newRegisterUser.getAvatar());

//            saveToES.setPhone(phone);
            userInfoTopic.setManager(saveToES);
            try {
                JSONObject body = new JSONObject();
                body.put("topic", userInfoTopic);
                searchService.index(body);
                logger.info("aliAuthLogin:保存新用户信息到ES成功，uId:{}", newRegisterUser.getuId());
            } catch (Exception e) {
                logger.error("aliAuthLogin:保存新用户信息到ES 出错，uId:{}", newRegisterUser.getuId());
            }
            //保存用户信息到 阿里百川
//            Userinfos userinfos = new Userinfos();
//            userinfos.setUserid(newRegisterUser.getuId());
//            userinfos.setPassword(newRegisterUser.getPassword());
//            userinfos.setNick(newRegisterUser.getNick());
//            userinfos.setName(newRegisterUser.getUsername());
//            userinfos.setIconUrl(newRegisterUser.getAvatar());
//            OpenimUsersAddRequest requestAiPay = new OpenimUsersAddRequest();
//            String userInfo = com.taobao.api.internal.util.StringUtils.toUnderlineStyle(JSON.toJSONString(userinfos));
//            requestAiPay.setUserinfos(userInfo);
//            try {
//                OpenimUsersAddResponse responseAliPay = taobaoClient.execute(requestAiPay);
//                if (!responseAliPay.isSuccess()) {
//                    logger.error("aliAuthLogin:注册新用户到阿里百川出错" + responseAliPay.getSubCode() + "   " + responseAliPay.getSubMsg());
//                } else {
//                    logger.info("aliAuthLogin:注册新用户到阿里百川完成" + newRegisterUser.getuId());
//                }
//            } catch (ApiException e) {
//                logger.error("restRegister:注册新用户信息到阿里百川出错", e);
//                e.printStackTrace();
//            }
            String salt = Utils.genSalt();//生成 盐
            String token = JwtTokenUtils.genToken(salt, newRegisterUser.getuId());
            newRegisterUser.setSalt(salt);
            newRegisterUser.setCreated(null);//清掉用不着缓存的用户信息
            saveUserInfoToRedis(newRegisterUser);
            redisTemplate.expire(Constant.USER_SESSION + newRegisterUser.getuId(), 30, TimeUnit.DAYS);//设置登录用户信息缓存过期时间
//            String token = IDUtils.genUUID();
            //将敏感字段设置为空
            newRegisterUser.setSalt(null);
            newRegisterUser.setPassword(null);
            newRegisterUser.setPayPassword(null);
            Map<String, Object> resultMap = new HashMap<>();
            resultMap.put("token", token);
            resultMap.put("userInfo", newRegisterUser);
            return CommonResult.ok(resultMap);

        }

    }

    /**
     * 绑定支付宝账户
     *
     * @param info
     * @return
     */
    @PostMapping("/bindAliPay")
    @SerializedField(encrypt = false)
    public CommonResult bindAliAccount(@RequestBody Map<String, String> info) {
        String uId = request.getHeader("uId");
        logger.info("bindAliAccount:bindAliPay:需要绑定的账户:uId:{}", uId);
        //获取支付宝账户
        String aliAccount = info.get("aliAccount");
        //更新到数据库中
        User addAliAccountUser = new User();
        addAliAccountUser.setAliAccount(aliAccount);
        addAliAccountUser.setuId(uId);
        int count = userMapper.updateByPrimaryKeySelective(addAliAccountUser);
        logger.info("需要绑定的支付宝账户:uId:{},aliAccount:{}");
        redisTemplate.opsForHash().put(Constant.USER_SESSION + uId, "aliAccount", aliAccount);
        logger.info("支付宝账户绑定成功");
        //将绑定的支付宝账户返回到客户端
        return CommonResult.ok(aliAccount);
    }

    /**
     * 本来客户端通过授权后，就能获取用户支付宝uid,只是没有签名验证等过程，担心信息不准确，中间是否有可能被篡改？？？
     *
     * @return
     * @throws AlipayApiException
     */
//    @PostMapping("/bindAliPay")
    public CommonResult bindAliPay(@RequestBody Map<String, String> info) throws AlipayApiException {
        String uId = request.getHeader("uId");
        logger.info("bindAliPay:需要绑定的账户:uId:{}", uId);
        CommonResult commonResult = getAliPayUserInfo(info);
        if (!Constant.RETURN_HTTP_STATUS_SUCCESS.equals(commonResult.getStatus())) {
            return commonResult;
        }
        //获取支付宝id
        AlipayUserInfoShareResponse shareResponse = (AlipayUserInfoShareResponse) commonResult.getData();
        String aliUid = shareResponse.getUserId();
        UserExample example = new UserExample();
        UserExample.Criteria criteria = example.createCriteria();
        criteria.andAliUidEqualTo(aliUid);
        List<User> tbUsers = userMapper.selectByExample(example);
        //判断在平台上是否已经有人使用了该支付宝账号
        if (tbUsers.size() > 0) {
            //获取该账户的信息
            User authUser = tbUsers.get(0);
            //判断该账户是否已经绑定了手机号
            String phone = authUser.getPhone();
            if (!StringUtils.isEmpty(phone)) {
                //如果已经有人使用该支付宝账户绑定了手机号,则用户不能重新绑定
                logger.info("支付宝账户已经被绑定了:uId:{},aliUid:{}", uId, aliUid);
                return CommonResult.build(Constant.RETURN_HTTP_STATUS_ALIUSER_EXIT, "支付宝账户已经被绑定了");
            }
            //如果没人使用该支付宝账户绑定手机号,则用户可以绑定支付宝
            //同步授权用户与原始注册用户之间的数据
            logger.info("授权用户与注册用户开始同步数据:uId:{},authId:{}", uId, authUser.getuId());
            User originalUserInfo = getUser(uId);
            //同步基本字段信息
            authSetOriginalUser(authUser, originalUserInfo);
            //同步收货地址信息
            List<OrderReceiveInfo> registerOrderReceiveInfoList = originalUserInfo.getOrderReceiveInfos(); //注册用户收货地址
            List<OrderReceiveInfo> authUserOrderReceiveInfoList = authUser.getOrderReceiveInfos();//授权用户收货地址
            if (registerOrderReceiveInfoList == null) {
                registerOrderReceiveInfoList = authUserOrderReceiveInfoList;
            } else {
                registerOrderReceiveInfoList.addAll(authUserOrderReceiveInfoList);
            }
            originalUserInfo.setOrderReceiveInfos(registerOrderReceiveInfoList);
            logger.info("同步数据完成:uId:{},aliUid:{}", uId, aliUid);
            //更新注册用户的信息
            userController.upDateUserInfo(originalUserInfo);
            //删除授权用户的信息
            userController.deleteUserInfo(authUser);
            //将敏感字段设置为空
            originalUserInfo.setPassword(null);
            originalUserInfo.setPayPassword(null);
            originalUserInfo.setSalt(null);
            //物理删除授权用户的信息
            Map<String, Object> resultMap = new HashMap<>();
            resultMap.put("userInfo", originalUserInfo);
            return CommonResult.ok(resultMap);
        }
        User updateUser = new User(uId);
        updateUser.setAliUid(aliUid);
        redisTemplate.opsForHash().put(Constant.USER_SESSION + uId, "aliUid", aliUid);
        userMapper.updateByPrimaryKeySelective(updateUser);
// TODO: 2018/8/28 应该在客户端显示绑定的支付宝信息，比如支付宝的登录id,但是获取的支付宝信息中没有此信息，官方技术论坛说要特别权限，才能获取，
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("aliUid", aliUid);
        return CommonResult.ok(resultMap);
    }

    /**
     * 发红包走支付宝，获取支付链接
     *
     * @param coupon
     * @return
     * @throws Exception
     */
    @PostMapping("/getCouponUrl")
    public CommonResult getCouponUrl(@RequestBody Coupon coupon) throws Exception {

        AlipayFundCouponOrderAppPayRequest fundCouponRequest = new AlipayFundCouponOrderAppPayRequest();
        fundCouponRequest.setNotifyUrl(aliPayConfig.NOTIFY_URL_FUND_COUPON);
        AlipayFundCouponOrderAppPayModel model = new AlipayFundCouponOrderAppPayModel();
        String outOderNo = IDUtils.genOrderItemId();
        String outRequestNo = IDUtils.genOrderId();
        model.setOutOrderNo(outOderNo);
        model.setOutRequestNo(outRequestNo);
        model.setOrderTitle("发送红包");
        model.setAmount(String.valueOf(coupon.getAmount()));
        model.setExtraParam("发给张三");

        fundCouponRequest.setBizModel(model);

        String fundCouponRequestUrl = alipayClient.sdkExecute(fundCouponRequest).getBody();
        //补充红包信息的基本信息，并缓存
        coupon.setId(outOderNo);
        coupon.setOutRequestNo(outRequestNo);
        coupon.setCreated(new Date());
        coupon.setStatus(Constant.COUPON_STATUS_RECEIVABLE);
        // redis hash 不能设置过期时间，所以还是保存为string
        // redisTemplate.opsForHash().putAll(redisKeyConfig.FUND_COUPON+outOderNo,EntityUtils.objectToMap(coupon));
        redisTemplate.opsForValue().set(Constant.FUND_COUPON + outOderNo, JSONObject.toJSONString(coupon), 25, TimeUnit.HOURS);
        //因为没上线，没法测试红包无线支付，为了先测试起走，这儿返回 红包id,
        //  return CommonResult.ok(fundCouponRequestUrl);
        return CommonResult.ok(outOderNo);
    }

    /**
     * 调用支付宝app发红包后，把收到的信息发送到这验证签名，签名完成，说明
     *
     * @return
     */
    @PostMapping("/aliCouponValidateSign")
    public CommonResult aliCouponValidateSign(@RequestBody String outOrderNo) {//现在测试，传的是id
        //String outOrderNo = body.getString("outOrderNo");
// TODO: 2018/9/2 这儿是验证签名过程

        String key = Constant.FUND_COUPON + outOrderNo;
        RedisLock lock = new RedisLock(redisTemplate, key);
        try {
            if (!lock.lock()) {
                logger.info("发红包同步通知验签：未获取到锁,直接返回");
                return CommonResult.build(Constant.GET_LOCK_FAIL, "发红包同步验证签名获取锁失败");
            }
            Object fundCouponStr = redisTemplate.opsForValue().get(key);
            if (fundCouponStr == null) {
                logger.error("发红包同步通知验签：redis找不到缓存记录");
                return CommonResult.build(Constant.FUND_COUPON_EOOR, "该红包没找到对应的缓存记录");
            }
            Coupon coupon = (Coupon) fundCouponStr;
            coupon.setStatus(Constant.COUPON_STATUS_RECEIVED);//状态1 标识 已经同步验证签名了
            coupon.setType(Constant.COUPON_TYPE_ALI_FUND);
            redisTemplate.opsForValue().set(key, JSONObject.toJSONString(coupon));//更改红包状态后，缓存到redis,1表示此红包记录，已经持久化到mysql
            //持久化
            couponMapper.insertSelective(coupon);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }

        return CommonResult.ok();
    }

    /**
     * 发红包后，接收支付宝异步通知，验证签名
     */
    @PostMapping("/aliFundCouponNotify")
    public String aliFundCouponNotify(HttpServletRequest request) throws AlipayApiException {
        Map<String, String> params = analyzeRequestParams(request);
        logger.info("发红包异步通知验签:" + params);
        boolean flag = checkSign(params);

        if (!flag) {
            logger.error("发红包异步通知验签失败" + params);
            return "fail";
        }
        String auth_no = params.get("auth_no");//支付宝的资金授权订单号
        String outOrderNo = params.get("out_order_no");//商户的授权资金订单号
        String operation_id = params.get("operation_id");//支付宝的资金操作流水号
        String out_request_no = params.get("out_request_no");//商户本次资金操作的请求流水号
        String amount = params.get("amount");
        String statuse = params.get("status");//资金预授权明细的状态    目前支持： INIT：初始     SUCCESS: 成功   CLOSED：关闭
        String gmt_trans = params.get("gmt_trans");//资金授权成功时间       格式：YYYY-MM-DD HH:MM:SS
        //读取缓存中的发红红包信息
        String key = Constant.FUND_COUPON + outOrderNo;
        RedisLock lock = new RedisLock(redisTemplate, key);
        try {
            if (!lock.lock()) {
                logger.info("发红包异步通知验签：为获取到锁，直接返回" + params);
                return "success";
            }
            Object fundCouponStr = redisTemplate.opsForValue().get(key);
            Coupon coupon;
            if (fundCouponStr != null) {
                coupon = (Coupon) fundCouponStr;
                //状态是1，表示在同步通知中已经做了持久化操作
                if (coupon.getStatus() == Constant.COUPON_STATUS_RECEIVED) {
                    return "success";
                } else {
                    coupon.setStatus(Constant.COUPON_STATUS_RECEIVED);
                    redisTemplate.opsForValue().set(key, JSONObject.toJSONString(coupon));//这儿更新状态1到redis是为了：避免在发红包的同步通知中，也往mysql保存该条红包记录。
                }

            } else {
                logger.error("发红包，收到异步通知后，redis找不到缓存" + params);
                coupon = new Coupon();
                coupon.setOutRequestNo(outOrderNo);
                coupon.setAmount(new BigDecimal(amount));
                coupon.setOutRequestNo(out_request_no);
            }
            coupon.setAuthNo(auth_no);
            coupon.setOperationId(operation_id);
            coupon.setStatus(Integer.valueOf(statuse));
            coupon.setCreated(DateUtils.getDateByStr(gmt_trans));
            couponMapper.insertSelective(coupon);


        } catch (InterruptedException e) {
            e.printStackTrace();
            logger.info("发红包异步通知验签:没获取到锁");

        } finally {
            lock.unlock();
        }

        return "success";
    }


    /**
     * 接收支付宝红包
     *
     * @param coupon
     * @return
     */
    @PostMapping("/receiveFundCoupon")
    public CommonResult receiveFundCoupon(@RequestBody Coupon coupon) {
        String uId = request.getHeader("uId");
        String key = Constant.FUND_COUPON + coupon.getId();
        RedisLock lock = new RedisLock(redisTemplate, Constant.USER_SESSION_LOCK + uId);
        try {
            if (!lock.lock()) {
                return CommonResult.build(Constant.GET_LOCK_FAIL, "领取红包，获取锁失败了");
            }
            Object fundCouponString = redisTemplate.opsForValue().get(key);
            if (fundCouponString == null) {
                coupon.setStatus(Constant.COUPON_STATUS_EXPIRED);
                return CommonResult.build(Constant.FUND_COUPON_STATUS_EXPIRED, "红包已经过期");
            }
            if (!StringUtils.equals(coupon.gettId(), uId)) {
                return CommonResult.build(Constant.FUND_COUPON_TARGET_USER_MISMATCHING, "红包接收人不匹配");
            }
// TODO: 2018/9/8 如果后续接入了支付宝红包，那就在这调用支付宝的红包打款接口，红包款项直接进入红包接收者绑定的支付宝账户
            return CommonResult.ok();
        } catch (InterruptedException e) {
            e.printStackTrace();
            return CommonResult.build(Constant.FUND_COUPON_EOOR, "发红包出错，未知错误");
        } finally {
            lock.unlock();
        }

    }


    private Map<String, String> analyzeRequestParams(HttpServletRequest request) {
        Map<String, String> params = new HashMap<String, String>();
        Map requestParams = request.getParameterMap();
        for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i]
                        : valueStr + values[i] + ",";
            }
//            if (name.equals("trade_status")) {
//
//                System.out.println("交易状态为：" + valueStr);
//
//            }
            //乱码解决，这段代码在出现乱码时使用。
            //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
            params.put(name, valueStr);
        }
        return params;
    }

    /**
     * 获取支付宝账户信息
     *
     * @param info
     * @return
     */
    private CommonResult getAliPayUserInfo(Map<String, String> info) throws AlipayApiException {
        String auth_code = info.get("auth_code");
        AlipaySystemOauthTokenRequest request = new AlipaySystemOauthTokenRequest();//创建API对应的request类
        //使用authCode获取asstoken
        request.setGrantType(aliPayConfig.GRANT_TYPE);
        request.setCode(auth_code);
        AlipaySystemOauthTokenResponse response = alipayClient.execute(request);//通过alipayClient调用API，获得对应的response类
        logger.info("获取支付宝token" + response.getBody());
        if (!response.isSuccess()) {
            logger.error("获取支付宝token" + response.getBody());
            return CommonResult.build(Constant.ALI_AUTH_CODE_INVALID, "支付宝授权码无效");
        }
        // String accessToken = token_response.getString("access_token");
        String accessToken = response.getAccessToken();
        AlipayUserInfoShareRequest infoShareRequest = new AlipayUserInfoShareRequest();
        AlipayUserInfoShareResponse shareResponse = alipayClient.execute(infoShareRequest, accessToken);
        if (!shareResponse.isSuccess()) {
            logger.error("获取支付宝授权用户信息" + response.getBody());
            return CommonResult.build(Constant.ALI_SYSTEM_ERROR, "支付宝系统错误");
        }
        return CommonResult.ok(shareResponse);
    }

    private boolean checkSign(Map<String, String> params) throws AlipayApiException {
        //切记alipaypublickey是支付宝的公钥，别错放应用公钥，如果再验签这出问题，先排查是否放错公钥，一般是这个问题造成
        //boolean AlipaySignature.rsaCheckV1(Map<String, String> params, String publicKey, String charset, String sign_type)
        return AlipaySignature.rsaCheckV1(params, aliPayConfig.ALI_PAY_PUBLIC_KEY, aliPayConfig.CHARSET, aliPayConfig.SIGN_TYPE);
    }

    private void saveUserInfoToRedis(@RequestBody User user) {
        try {
            Map map = EntityUtils.objectToMap_v1(user);
            redisTemplate.opsForHash().putAll(Constant.USER_SESSION + user.getuId(), map);
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("restLogin:缓存用户信息失败：" + e.getMessage());
        }
    }

    /**
     * 根据用户id获取用户的信息
     *
     * @param uId
     * @return
     */
    private User getUser(String uId) {
            Map<Object, Object> entries = redisTemplate.opsForHash().entries(Constant.USER_SESSION + uId);
            if(entries.isEmpty()){
                return  userMapper.selectByPrimaryKey(uId);
            }
            return JSONObject.parseObject(JSONObject.toJSONString(entries), User.class);
    }

    /**
     * 使用负载均衡算法获取处理当前提现订单的管理员id
     *
     * @return
     */
    private List<String> getTransferAdminId() {
        count = MytxConfig.adminIdList.size();
        int index = reqCount++ % count;
        List<String> userIdList = new ArrayList<>();
        String adminId =  MytxConfig.adminIdList.get(index);
        logger.info("当前转账订单负责的管理员:adminId:{}", adminId);
        userIdList.add(adminId);
        return userIdList;
    }

    /**
     * 将授权用户的数据同步到原始用户中
     *
     * @param authUser
     * @param originalUserInfo
     */
    private void authSetOriginalUser(User authUser, User originalUserInfo) {
        BigDecimal authBalace = authUser.getBalance();
        BigDecimal registerBalace = originalUserInfo.getBalance();
        BigDecimal authDeposit = authUser.getDeposit();
        BigDecimal registerDeposit = originalUserInfo.getDeposit();
        logger.info("注册用户的余额:registerBalace:{},注册用户的保证金:registerDeposit:{}", registerBalace, registerDeposit);
        logger.info("授权用户的余额:authBalact:{},注册用户的保证金:authDeposit:{}", authBalace, authDeposit);
        if (authBalace != null) {
            originalUserInfo.setBalance(authBalace.add(registerBalace));
        }
        if (authDeposit != null) {
            originalUserInfo.setDeposit(authDeposit.add(registerDeposit));
        }
        originalUserInfo.setAliUid(authUser.getAliUid());
        BigDecimal authDonationAmount = authUser.getDonationAmount();
        BigDecimal registerDonationAmout = originalUserInfo.getDonationAmount();
        BigDecimal authDonationBalance = authUser.getDonationBalance();
        BigDecimal registerDonationBalance = originalUserInfo.getDonationBalance();
        BigDecimal authDonationReceived = authUser.getDonationReceived();
        BigDecimal registerDonationReceived = originalUserInfo.getDonationReceived();
        logger.info("注册用户的registerDonationAmout:{},注册用户的registerDonationBalance:{},注册用户的registerDonationReceived:{}",
                registerDonationAmout, registerDonationBalance, registerDonationReceived);
        logger.info("授权用户的authDonationAmout:{},授权用户的authDonationBalance:{},授权用户的authDonationReceived:{}",
                authDonationAmount, authDonationBalance, authDonationReceived);
        if (authDonationAmount != null) {
            originalUserInfo.setDonationAmount(authDonationAmount.add(registerDonationAmout));
        }
        if (authDonationBalance != null) {
            originalUserInfo.setDonationBalance(authDonationBalance.add(registerDonationBalance));
        }
        if (authDonationReceived != null) {
            originalUserInfo.setDonationReceived(authDonationReceived.add(registerDonationReceived));
        }
        originalUserInfo.setUpdated(new Date());
    }




}
